package demo.log.log4j;

import com.ximalaya.xdcs.client.logimpl.LogEventDes;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.ThrowableInformation;
import demo.log.model.GenericLogEvent;
import org.apache.log4j.spi.LoggingEvent;

import java.io.PrintWriter;
import java.io.StringWriter;

public class Log4jEventAdapter implements GenericLogEvent {

    private final LoggingEvent event;

    public Log4jEventAdapter(LoggingEvent event) {
        this.event = event;
    }

    @Override
    public LogEventDes parseLogEvent() {
        if (event == null){
            return null;
        }

        Level logLevel = Level.toLevel(null, Level.ERROR);
        if (event.getLevel().toInt()<logLevel.toInt()){
            return null;
        }

        LogEventDes logEventDes = new LogEventDes();
        try {
            logEventDes.setLogLevelDes(event.getLevel().toString());
            logEventDes.setLogDetail(String.valueOf(event.getMessage()));
            logEventDes.setThreadName(event.getThreadName());
            logEventDes.setLogName(event.getLoggerName());
            logEventDes.setMessage(String.valueOf(event.getMessage()));

            if (Level.ERROR.equals(event.getLevel()) || Level.FATAL.equals(event.getLevel())) {

                ThrowableInformation errorInfo = event.getThrowableInformation();

                Throwable error;
                if (errorInfo != null) {
                    error = event.getThrowableInformation().getThrowable();
                    String errorClassName = error.getClass().getName();
                    logEventDes.setLogIdentity(errorClassName);
                    StringWriter buf = new StringWriter();
                    error.printStackTrace(new PrintWriter(buf));
                    logEventDes.setLogDetail(buf.toString());
                    // 获得抛出异常的方法名称
                    StackTraceElement[] stackTrace = error.getStackTrace();
                    if (stackTrace.length == 0) {
                        logEventDes.setMethodName("unkown");
                    } else {
                        StackTraceElement lastElem = stackTrace[0]; // ArrayOutOfBoundException
                        logEventDes.setMethodName(lastElem.getClassName() + ":" + lastElem.getMethodName());
                        logEventDes.setLogIdentity(lastElem.getClassName() + ":" + lastElem.getMethodName() + ":" + lastElem.getLineNumber());
                    }

                }
            }

            if (StringUtils.isBlank(logEventDes.getLogIdentity())) {
                LocationInfo locationInfo = event.getLocationInformation();
                if (locationInfo!=null) {
                    StringBuilder sBuilder = new StringBuilder(locationInfo.getClassName());
                    String methodName = locationInfo.getMethodName();
                    String className = locationInfo.getClassName();
                    sBuilder.append(":");
                    sBuilder.append(methodName);
                    sBuilder.append(":");
                    sBuilder.append(locationInfo.getLineNumber());
                    logEventDes.setLogIdentity(sBuilder.toString());
                    logEventDes.setMethodName(className + ":" + methodName);
                }else {
                    logEventDes.setLogIdentity("unknown");
                    logEventDes.setMethodName("unknown");
                }
            }
        } catch (Throwable ex) {
            LogLog.error("handle parseLogEvent error", ex);
        }

        return logEventDes;
    }
}
